﻿<?php
/**
 * @version		$Id: geotrails.php 20196 2011-08-06 00:00:00Z jerome $
 * @package		Vsb.Site
 * @subpackage	com_geotrails
 * @copyright	Copyright (C) 2011 Verbier Technologies Sàrl, Inc. All rights reserved.
 * @license		GNU General Public License version 2 or later
 */

// No direct access to this file
defined('_JEXEC') or die('Restricted access');
 
jimport('joomla.application.component.model');
jimport('joomla.application.component.helper');
jimport('joomla.application.component.modelitem');
 
/**
 * GeoTrails Model
 *
 * @package		Vsb.Site
 * @subpackage	com_geotrails
 * @since 1.7
 *
 */

class GeoTrailsModelGeoTrails extends JModelItem {

	// @var SimpleXML trails
	public $trails;
	// @var string api_url_base
	public $api_url_base = "";
	// @var string api_url_kml
	public $api_url_kml = "";
	// @var string api_url_profile
	public $api_url_profile = "";
	// @var string data folder
	public $xml_folder = "/xml_data/";
	// @var string lang folder
	public $lang_folder = "";	
	// @var params
	protected $_params;

	// Redéfinition du constructor pour loader automatiquement les paramètres du composant
	function __construct($config = array()) {
			
		// Récupère les paramètres du composant
		$application   =& JFactory::getApplication();
		$this->_params = $application->getParams('com_geotrails');
		
		// Aucune API définie
		if (!strlen($this->_params->get('api_url_base')) || !strlen($this->_params->get('api_url_kml')) || !strlen($this->_params->get('api_url_profile'))) {
			JFactory::getApplication()->enqueueMessage( JText::_('COM_GEOTRAILS_VIEW_ERROR_2') );
			return false;
		}
		
		// Adresse URL des APIs Geotrails
		$this->api_url_base    = $this->_params->get('api_url_base');
		$this->api_url_kml     = $this->_params->get('api_url_kml');
		$this->api_url_profile = $this->_params->get('api_url_profile');
		$this->xml_folder      = $this->_params->get('xml_folder');
		
		// Appel du constructeur parent
		parent::__construct();	
	}	
	
	/**
	 * Récupère la liste des randonnées d'un région
	 * @return un objet SimpleXMLElement des valeurs
	 */
	public function getTrails($params = false) {

		if (!$params) {
			$params = $this->_params;
		}
		
		// Récupère le language courant pour créer le dossier adéquat
		$lang =& JFactory::getLanguage();
		$this->lang_folder = $lang->getTag();
		
		// Répertoire par défaut des fichiers XML du cache, si configuré
		if (strlen($this->xml_folder)) {
			$this->xml_folder = $this->xml_folder.DS.'com_geotrails'.DS.$this->lang_folder.DS;
		} else {
			$this->xml_folder = JPATH_COMPONENT_SITE.$this->xml_folder.$this->lang_folder.DS;
		}

		$this->xml_folder = JPATH_SITE.DS.$this->xml_folder;
		
		// Test si le répertoire existe, si pas, on le créé
		if (!JFolder::exists($this->xml_folder)) {
			JFolder::create($this->xml_folder);
		}
				
		// Si un ID de trail est défini -> view = fiche
		$option = JRequest::getCmd('option');
		$view   = JRequest::getCmd('view');

		if ($view == "fiche") {
			// Récupère l'ID de fiche
			$trail_id = JRequest::getInt('id');
			
			// Récupère l'ID de la fiche par le paramètre
			if (!$trail_id) {
				$trail_id = $params->get('trail_id');
				
				// Aucun ID de fiche dans les paramètres !
				if (!$trail_id) {
					JFactory::getApplication()->enqueueMessage( JText::_('COM_GEOTRAILS_VIEW_ERROR_1') );
					return false;
				}
			}
		}

		// Pagination
		if ($params->get('show_paginate')) {
			$session =& JFactory::getSession();

			if (!$session->get("paginate_geotrails")) {
				$session->set("paginate_geotrails", $params->get('paginate_value'));
			} else {
				if (JRequest::getInt('paginate')) {
					$session->set("paginate_geotrails", $session->get("paginate_geotrails") + $params->get('paginate_value'));
				}
			}
		}
		
		$xml_date = date("d-m-Y");
		
		// Création des noms de fichiers selon la date du jour
		if ($trail_id) {
			$file     = 'trail_' . $trail_id . '_' . $xml_date . '.xml';
			$filename = $this->xml_folder . $file;
			$masque   = 'trail_' . $trail_id . '*.xml';
			
			$kml_file     = 'kml_' . $trail_id . '.kml';
			$kml_filename = $this->xml_folder . $kml_file;
			
			// Le fichier KML associé au trail n'existe pas, on le créé
			if (!JFile::exists($kml_filename)) {
				if (!$this->createKmlFile($trail_id, $kml_filename)) {
					JFactory::getApplication()->enqueueMessage( JText::_('COM_GEOTRAILS_VIEW_ERROR_8') );
				}
			}

			$profil_file     = 'profil_' . $trail_id . '.png';
			$profil_filename = $this->xml_folder . $profil_file;
			
			// Le fichier de profil (.png) associé au trail n'existe pas, on le créé
			if (!JFile::exists($profil_filename)) {
				if (!$this->createProfilFile($trail_id, $profil_filename)) {
					JFactory::getApplication()->enqueueMessage( JText::_('COM_GEOTRAILS_VIEW_ERROR_9') );
				}
			}
		} else {
			$file     = 'trails_' . $xml_date . '.xml';
			$filename = $this->xml_folder . $file; 	
			$masque   = 'trails_*.xml';
		}
				
		// Le fichier XML existe déjà
		if (JFile::exists($filename)) {
			$this->trails = JFile::read($filename);
			return $this->trails = new SimpleXMLElement($this->filterTrails(), LIBXML_NOCDATA);
		}
		
		// Le fichier XML n'existe pas, on le créé
		
		// On appelle l'API pour récupérer les trails
		$trails = $this->getTrailsFromAPI($trail_id);
		
		// Ecriture du fichier cache dans le filesystem
		if (JFile::write($filename, $trails)) {
			// On supprimer l'ancien fichier du cache
			$this->removeOldFile($masque);

			$this->trails = JFile::read($filename);
			return $this->trails = new SimpleXMLElement($this->filterTrails(), LIBXML_NOCDATA);
		}
		
		// Erreur lors de l'écriture du fichier de cache, on récupère un ancien fichier
		$this->trails = JFile::read($this->loadOldFile($masque));
		return $this->trails = new SimpleXMLElement($this->filterTrails(), LIBXML_NOCDATA);
	}
	
	/**
	* Appel à l'API Geotrails.ch
	* @return string tampon XML des valeurs
	*/
	private function getTrailsFromAPI($trail_id) {
		/* HTTP request section	*/
		$ch = curl_init();
		
		curl_setopt($ch, CURLOPT_URL, $this->api_url_base);
		
		/* SSL Verification options - always false */
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
	
		/* HTTP protocol and stream options */
		curl_setopt($ch, CURLOPT_FAILONERROR, 1);
		//curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);	// allow redirects
		curl_setopt($ch, CURLOPT_TIMEOUT, 90); 			// times out after 90s
		curl_setopt($ch, CURLOPT_POST, 1); 				// set POST method
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 	// return into a variable. This is IMPORTANT!

		$lang_code = $this->lang_folder[0].$this->lang_folder[1];
		
		/* add POST body */
		if ($trail_id) {
			$filter = array('lang' => $lang_code, 'trailid' => $trail_id);
		} else {
			$filter = array('lang' => $lang_code, 'export' => 'all');
		}
		
		curl_setopt($ch, CURLOPT_POSTFIELDS, $filter); // add POST fields
		
		/* run the whole process. returns the requested XML structure on success, FALSE on failure */
		$trails = curl_exec($ch);	
		curl_close($ch); 
		
		if (!$trails) {
			if (!$this->loadOldFile()) {
				JFactory::getApplication()->enqueueMessage( JText::_('COM_GEOTRAILS_VIEW_ERROR_3') );
				return false;
			}
		} else {
			if (strstr(!$trails, '<trails>')) {
				if (!$this->loadOldFile()) {
					JFactory::getApplication()->enqueueMessage( JText::_('COM_GEOTRAILS_VIEW_ERROR_4') );
					return false;
				}
			}
		}
		
		// Evite des le caractère intempestif "&" qui invalide le fichier XML
		return str_replace('&', '', $trails);
	}

	/**
	* Appel à l'API Geotrails.ch
	* @return string tampon XML des valeurs
	*/
	private function createKmlFile($trail_id, $kml_filename) {
		/* HTTP request section	*/
		$ch = curl_init();
		
		curl_setopt($ch, CURLOPT_URL, $this->api_url_kml.$trail_id);
		
		/* SSL Verification options - always false */
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
	
		/* HTTP protocol and stream options */
		curl_setopt($ch, CURLOPT_FAILONERROR, 1);
		//curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);	// allow redirects
		curl_setopt($ch, CURLOPT_TIMEOUT, 90); 			// times out after 90s
		curl_setopt($ch, CURLOPT_POST, 0); 				// set POST method
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 	// return into a variable. This is IMPORTANT!

		/* run the whole process. returns the requested XML structure on success, FALSE on failure */
		$kml = curl_exec($ch);	
		curl_close($ch);
		
		if (!$kml) {
			JFactory::getApplication()->enqueueMessage( JText::_('COM_GEOTRAILS_VIEW_ERROR_3').' [KML]' );
			return false;
		}
		
		if (!JFile::write($kml_filename, $kml)) {
			JFactory::getApplication()->enqueueMessage( JText::_('COM_GEOTRAILS_VIEW_ERROR_5') );
			return false;
		}
		
		return true;
	}

	/**
	* Appel à l'API Geotrails.ch
	* @return string tampon XML des valeurs
	*/
	private function createProfilFile($trail_id, $profil_filename) {
		/* HTTP request section	*/
		$ch = curl_init();
		
		curl_setopt($ch, CURLOPT_URL, $this->api_url_profile.$trail_id);
		
		/* SSL Verification options - always false */
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
	
		/* HTTP protocol and stream options */
		curl_setopt($ch, CURLOPT_FAILONERROR, 1);
		//curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);	// allow redirects
		curl_setopt($ch, CURLOPT_TIMEOUT, 90); 			// times out after 90s
		curl_setopt($ch, CURLOPT_POST, 0); 				// set POST method
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 	// return into a variable. This is IMPORTANT!

		/* run the whole process. returns the requested XML structure on success, FALSE on failure */
		$profil = curl_exec($ch);	
		curl_close($ch); 
		
		if (!$profil) {
			JFactory::getApplication()->enqueueMessage( JText::_('COM_GEOTRAILS_VIEW_ERROR_3').' [Profil]' );
			return false;
		}
		
		if (!JFile::write($profil_filename, $profil)) {
			JFactory::getApplication()->enqueueMessage( JText::_('COM_GEOTRAILS_VIEW_ERROR_6') );
			return false;
		}
		
		return true;
	}
	
	/**
	* Detruit la plus vieille version 
	* @return boolean
	*/
	private function removeOldFile($masque){
		// glob: Recherche des chemins qui vérifient un masque
		$list = glob($this->xml_folder.$masque);
		
		// Génère un tableau associatif pour un tri sur la date
		foreach ($list as $file) {
			$filetab[filemtime($file)] = $file;
		}
		
		// krsort: reverse sort by key on a array
		krsort($filetab);
		
		if (sizeof($filetab) > 1) {
			// Suppression du fichier
			return (JFile::delete(end($filetab)));
		}
	}
	
	/**
	* Charge la version la plus récente
	* @return string du nom de fichier
	*/
	private function loadOldFile($masque){		
		// glob: Recherche des chemins qui vérifient un masque
		$list = glob($this->xml_folder.$masque);

		// Génère un tableau associatif pour un tri sur la date
		foreach ($list as $file) {
			$filetab[filemtime($file)] = $file;
		}
		
		// krsort: reverse sort by key on a array
		krsort($filetab);
		
		// Renvoie le 1er nom de fichier trouvé.
		return reset($filetab);
	}
	
	/**
	* Filtre les randonnées, supprimer les noeuds qui ne sont pas dans le filtre
	* @return string tampon XML des valeurs
	*/
	public function filterTrails() {
		// Récupère la variable fields de la requête (module Geotrails)
		$fields = JRequest::getVar('fields');

		// Récupère les variables de la requête (URL)
		$thema        = JRequest::getVar('thema');
		$activityId   = JRequest::getVar('activityId');
		$difficultyId = JRequest::getVar('difficultyId');
		
		// Aucun champ de filtres
		if (!$fields && !$activityId && !$thema && !$difficultyId) {
			return $this->trails;
		}

		if ($fields){
			// Decode des valeurs JSON dans un tableau
			$fields = json_decode($fields);

			$filter = array();
	
			foreach ($fields as $field) {
				
				$fieldNameTmp = explode('_', $field->id);
				$field_name   = $fieldNameTmp[0];
				
				switch($field_name) {
					case 'activite':
						$filter['activityId'] = $field->value;
						break;
						
					case 'theme':
						$filter['thema'] = $field->value;
						break;
						
					case 'difficulte':
						$filter['difficultyId'] = $field->value;
						break;
				}
			}
		}

		//Préparation de tableau de filtre depuis l'URL
		if ($activityId) {
			$filter['activityId'] = $activityId; 
		}

		if ($thema) {
			$filter['thema'] = $thema;
			
		}

		if ($difficultyId) {
			$filter['difficultyId'] = $difficultyId; 
			
		}
		
		// Parse le document XML $ l'aide de DOM
		$dom = new DomDocument();
		$dom->loadXML($this->trails); 
		$root = $dom->documentElement;

		/*
		$pages  = $root->getElementsByTagName("pages");
		$p      = $pages->item(0);
		$parent = $p->parentNode;
		$parent->removeChild($p);
		*/

		$trails = $root->getElementsByTagName("trail");
		$length = $trails->length;

		for ($i=$length-1; $i>=0; $i--) {
		
			if (!$filter["activityId"][0] && !$filter["difficultyId"][0] && !$filter["thema"][0]) {
				continue;
			}
			
			if ($filter["activityId"][0]) {
				$found_activity  = false;
				$filter_activity = explode(",", $filter["activityId"]);
				$activity_id     = $root->getElementsByTagName('activity_id')->item($i)->nodeValue;
				
				if (in_array($activity_id, $filter_activity)) {
					$found_activity = true;
					
					if (!$filter["difficultyId"][0] && !$filter["thema"][0]) {
						continue;
					}
				}
			}
			
			if ($filter["thema"][0]) {
				$found_thema  = false;
				$filter_thema = explode(",", $filter["thema"]);
				
				$themas_node = $root->getElementsByTagName('themas')->item($i);
				$themas      = $themas_node->getElementsByTagName('thema');
				
				foreach($themas as $thema) {
					if (in_array($thema->getAttribute("id"), $filter_thema)) {
						$found_thema = true;
					}
				}
				
				if (!$filter["difficultyId"][0] && !$filter["activityId"][0] && $found_thema) {
					continue;
				}
			}
						
			if ($filter["difficultyId"][0]) {
				$found_difficulty  = false;
				$filter_difficulty = explode(",", $filter["difficultyId"]);
				$difficulty_id     = $root->getElementsByTagName('difficulty_id')->item($i)->nodeValue;
				
				if (in_array($difficulty_id, $filter_difficulty)) {
					$found_difficulty = true;

					if (!$filter["activityId"][0] && !$filter["thema"][0]) {
						continue;
					}
				}
			}
			
			// Test pour analyse combinatoire
			// Il est essentiel de tester les 3 critères simultanémanent
			// Les tests unitaires sont effectués plus haut
			if ($found_activity && $found_thema && $found_difficulty) {
				continue;
			}
						
			if ($found_activity && $found_difficulty && !$filter["thema"][0]) {
				continue;
			}
			
			if ($found_thema && $found_difficulty && !$filter["activityId"][0]) {
				continue;
			}
			
			if ($found_activity && $found_thema && !$filter["difficultyId"][0]) {
				continue;
			}
			
			$p = $trails->item($i);
			$parent = $p->parentNode;
			$parent->removeChild($p);
		}
		
		return $dom->saveXML();	
	}

	/**
	* Récupère le code de langue courant
	* @return string language code
	*/
	public function getLanguageCode() {
		$lang     =& JFactory::getLanguage();
		$lang_tag = $lang->getTag();
		
		return $lang_tag[0].$lang_tag[1];
	}
	
	/**
	* Récupère l'ID de la rubrique menu courante
	* @return int, Itemid
	*/
	public function getItemId() {
		$application =& JFactory::getApplication();
		
		$menu   = $application->getMenu();
		$active = $menu->getActive();
		
		return $active->id;
	}
	
	/**
	* Récupère le code de langue courant
	* @return string language code
	*/
	public function getTitle() {
		$application =& JFactory::getApplication();
		
		$menu   = $application->getMenu();
		$active = $menu->getActive();
		
		return $active->title;
	}

	/**
	* Génère une carte Google en fonction des trails
	* @return object Google Map
	*/
	public function getGoogleMap($trails, $center='Verbier, Suisse', $cluster=false, $width='100%', $height='400px', $zoom=8, $lang_code, $item_id) {
	
		if (!count($trails)) {
			return;
		}
		
		$gmap = new GoogleMapAPI();

		$gmap->setDivId('com_geotrails_map_display');
		$gmap->setEnableWindowZoom(true);
		$gmap->setEnableAutomaticCenterZoom(false);
		$gmap->setCenter($center);
		$gmap->setClusterer($cluster);
		$gmap->setSize($width, $height);
		$gmap->setZoom($zoom);
		$gmap->setLang($lang_code);
		$gmap->setDefaultHideMarker(false);

		foreach ($this->trails as $trail) {
			if (strlen($trail->lat) && strlen($trail->lng)) {
				$gmap->addMarkerByCoords($trail->lat, $trail->lng, $trail->title, GeoTrailsModelGeoTrails::setGoogleMapMarkerHtml($trail, $view, $item_id), 'activity_id_'.$trail->activity_id, JURI::root().'components/com_geotrails/assets/images/maps/activity_'.$trail->activity_id.'.png');
			}
		}
		
		$gmap->generate();
		
		return $gmap;
	}

	/**
	* Génère le code HTML de l'info-bulle pour les marques de Gmap
	* @return html
	*/
	public function setGoogleMapMarkerHtml($trail, $view = 'fiche', $item_id) {

		$html  = '<strong>'.$trail->title.'</strong><br /><br />';
		$html .= JText::_('COM_GEOTRAILS_GEOTRAILS_VIEW_CB_ACTIVITE').': '.JText::_('COM_GEOTRAILS_GEOTRAILS_VIEW_CB_ACTIVITE_'.$trail->activity_id).'<br />';
		$html .= JText::_('COM_GEOTRAILS_DIFFICULTY').': '.JText::_('COM_GEOTRAILS_DIFFICULTY_'.$trail->difficulty_id).'<br />';
		$html .= JText::_('COM_GEOTRAILS_DURATION').': '.$trail->duration.'<br />';
		$html .= "<a href='".JRoute::_(GeotrailsHelperRoute::getGeotrailsRoute($trail["id"], $trail->name, $item_id), false)."'>".JText::_('COM_GEOTRAILS_DETAIL')."</a><br /><br />";
		
		if (strlen($trail->picture)) {
			$html .= "<img src='".GeoTrailsModelGeoTrails::imageResize($trail->picture, 200, 120, 100)."' alt='".$fiche->raison_sociale."' />";
		}
	
		return $html;
	}
	
	/**
	* Retaille une image
	* @ param $image_path, $width, $height, $option
	* @return image_path de l'image retaillée
	*/
	public function imageResize($image_path, $width, $height, $quality=100, $option='exact') {
	
		if (!strlen($image_path) || !$width || !$height) {
			JFactory::getApplication()->enqueueMessage( JText::_('COM_GEOTRAILS_VIEW_ERROR_11') );
			return false;
		}

		// Récupère le paramètre de base pour le dossier du cache des images
		$application =& JFactory::getApplication();
		$params      = $application->getParams();
		
		if (!strlen($params->get('image_path_cache'))) {
			JFactory::getApplication()->enqueueMessage( JText::_('COM_GEOTRAILS_VIEW_ERROR_10') );
			return false;
		}
	
		$imageTmpArray = explode('/', $image_path);
		$indice        = count($imageTmpArray) - 1;
		$imageTmp      = $imageTmpArray[$indice];
		
		$image_path_resized = $params->get('image_path_cache').DS.'com_geotrails'.DS.'images'.DS.'resized'.DS.$width.'_'.$height.DS.$imageTmp;
		
		if (JFile::exists($image_path_resized)) {
			return str_replace('\\', '/', $image_path_resized);
		}
		
		// Test si le répertoire existe, si pas, on le créé
		$path_resized = $params->get('image_path_cache').DS.'com_geotrails'.DS.'images'.DS.'resized'.DS.$width.'_'.$height.DS;
		
		if (!JFolder::exists($path_resized)) {
			if (!JFolder::create(JPATH_SITE.'/'.$path_resized)) {
				JFactory::getApplication()->enqueueMessage( JText::_('COM_GEOTRAILS_VIEW_ERROR_12') );
				return false;			
			}
		}
		
		// Initialisation / load image
		$resizeImg = new resize($image_path);

		// Retaille l'image (options: exact, portrait, landscape, auto, crop)
		$resizeImg->resizeImage($width, $height, $option);

		// Enregistre l'image retaillée
		$resizeImg->saveImage(JPATH_SITE.'/'.$image_path_resized, $quality);
		
		return str_replace('\\', '/', $image_path_resized);
	}
}